/******************************************************************
 * Created by: GOh Chee Hong                                      
 * Date of Creation: 1/Jan/2009

 * 
 *                                                                
 * Description: This class is in charge of uploading file
 ******************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Threading;
using Pbdms.Common.CryptoUtils;
using Pbdms.Common.SharedVariables;
namespace Pbdms.BusinessLogic.Mail
{
    public class FileUploaderManager
    {
        private Hashtable fileattachments;
       
        public delegate void StatusHandler(object sender, string args);
        public StatusHandler statusProcess;
        public delegate Boolean checkCancel();
        public checkCancel isCancel;
        public FileUploaderManager()
        {

        }
        public FileUploaderManager(Hashtable fileattachments)
        {
            this.fileattachments = fileattachments;
           
        }
        public Boolean uploadFiles()
        {
            Boolean isUploaded = false;
            string msg = "";
            foreach (string key in fileattachments.Keys)
            {

                //string filelocation = (string)fileattachments[key];
                Hashtable twoFiles=  (Hashtable)fileattachments[key];
                ///twoFiles.Add("original", originalFileInfo.Name);
                //twoFiles.Add("signed", SignedFile);
                string originalFileName = (string)twoFiles["original"];
                string fileToUploaded= (string)twoFiles["signed"];
                System.IO.FileInfo fileInfo = new System.IO.FileInfo(fileToUploaded);
                int blocks= Common.Global.CalculateNoOfBlocks(fileInfo.Length);
                if (statusProcess != null)
                {
                    statusProcess(null, "(Signed) " +originalFileName + "(" + Common.Global.GetFileSize(fileInfo.Length) + ") uploading now");
                    Thread.Sleep(1000);
                }
                int workloads = blocks / 10; //10 uploaders
                int remainWorks = blocks % 10; //any remain works
                if (workloads <= 2)
                {   //do not distribute work
                    FileUploader fileUploader = new FileUploader(key, fileToUploaded, 0, blocks);
                    fileUploader.isCancel += new FileUploader.checkCancel(isCancel);
                    fileUploader.Upload();
                    isUploaded = fileUploader.IsUploaded();
                }
                else
                {
                    FileUploader[] fileUploader = new FileUploader[10];
                    Thread[] thfileUploader = new Thread[10];

                    for (int i = 0; i < 10; i ++)
                    {
                        int start_block = calStartBlock(i, remainWorks, workloads);
                        int eachWorkLoads = calWorkLoads(i, remainWorks, workloads);
                        fileUploader[i] = new FileUploader(key, fileToUploaded, start_block, eachWorkLoads);
                        fileUploader[i].isCancel += new FileUploader.checkCancel(isCancel);
                        thfileUploader[i] = new Thread(new ThreadStart(fileUploader[i].Upload));

                        thfileUploader[i].IsBackground = true;
                        thfileUploader[i].Start();
                    }
                    //check whether everyone has completed their job
                    int totalDone = 0;
                    for (int j = 0; j < 10; j++)
                    {
                        
                        //make sure the thread terminates
                        thfileUploader[j].Join();
                        totalDone += fileUploader[j].TotalBLocks;
                        if (fileUploader[j].IsUploaded() == true)
                        {

                            msg = totalDone + " of " + blocks + " file blocks (" + originalFileName + ") uploaded";
                            
                        }
                        else
                        {
                            msg = totalDone + " of " + blocks + " file blocks (" + originalFileName + ") cannot be uploaded\n The uploading operation is aborted";
                            
                        }
                        if (statusProcess != null)
                        {
                            isUploaded = true;
                            statusProcess(null, msg);
                            Thread.Sleep(2000);
                            if (fileUploader[j].IsUploaded() == false)
                            {
                                isUploaded = false;
                                break;
                            }
                        }
                    }
                }
                if(isUploaded==false){
                    //does not finished uploaded everything
                    msg = "Uploading of "+originalFileName+" is aborted";
                }else{
                    //finished uploaded everything
                    msg = "Finished uploading " + originalFileName;
                }
                if (statusProcess != null)
                {
                    statusProcess(null, msg);
                    Thread.Sleep(1000);
                }


                
            }
            return isUploaded;
        }

        private int calStartBlock(int i, int remainWorks, int eachWorkLoads)
        {
            if (remainWorks != 0)
            {
                //if i is less the amount of remainWorks
                if (i < remainWorks && i != 0)
                {
                    return ((i*eachWorkLoads)+i);
                }
                else if (i >= remainWorks)
                {
                    return ((i * eachWorkLoads) + remainWorks);
                }
                else
                {
                    return i;
                }
            }
            else
            {
                return (i * eachWorkLoads);//starting point
            }

        }
        private int calWorkLoads(int i, int remainWorks, int eachWorkLoads)
        {

            if (i < remainWorks)
            {
                return eachWorkLoads + 1;
            }
            else
            {
                return eachWorkLoads;
            }
        }
    }
}
